/*
 * NewJobFrame.java
 */

package gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormatSymbols;
import java.util.Calendar;
import java.util.GregorianCalendar;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;

import exceptions.UPException;

import model.Job;
import model.ListManager;
import model.Park;

/**
 * NewJobFrame displays a form to create a new Job object and add it to the list
 * of Jobs.
 * 
 * @author Sean Brown
 * @version 1.0
 */
@SuppressWarnings("serial")
public class NewJobFrame extends JFrame {

	/**
	 * The ListManager for this instance of the program.
	 */
	private final ListManager my_lm;

	/**
	 * The ManagerFrame that created this frame.
	 */
	private final ManagerFrame my_parent;

	/**
	 * The combo box for the list of park names.
	 */
	private JComboBox my_park_list;

	/**
	 * The ID numbers for the parks.
	 */
	private int[] my_park_ids;

	/**
	 * The text field for job description.
	 */
	private JTextField my_desc_field;

	/**
	 * The combo box for hour.
	 */
	private JComboBox my_hour;

	/**
	 * The combo box for minute.
	 */
	private JComboBox my_minute;

	/**
	 * The combo box to select am/pm.
	 */
	private JComboBox my_ampm;

	/**
	 * The combo box for month.
	 */
	private JComboBox my_month;

	/**
	 * The combo box for day.
	 */
	private JComboBox my_day;

	/**
	 * The combo box for year.
	 */
	private JComboBox my_year;

	/**
	 * The combo box for day duration.
	 */
	private JComboBox my_days;

	/**
	 * The combo box for hour duration.
	 */
	private JComboBox my_hours;

	/**
	 * The combo box for minute duration.
	 */
	private JComboBox my_minutes;

	/**
	 * The text field for heavy workers needed.
	 */
	private JTextField my_heavy;

	/**
	 * The text field for medium workers needed.
	 */
	private JTextField my_medium;

	/**
	 * The text field for light workers needed.
	 */
	private JTextField my_light;

	/**
	 * Constructor instantiates fields and sets up the JFrame.
	 * 
	 * @param the_parent
	 *            The ManagerFrame that created this frame.
	 * @param the_lm
	 *            The ListManager to get data from.
	 */
	public NewJobFrame(final ManagerFrame the_parent, final ListManager the_lm) {
		super("Add New Job");
		my_lm = the_lm;
		my_parent = the_parent;
	}

	/**
	 * Sets up all panels, preferences, and shows the frame on screen.
	 */
	public void start() {
		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		UIManager.put("Panel.background", Color.WHITE);

		final JPanel new_job_panel = new JPanel(new BorderLayout());
		new_job_panel.add(entryPanel(), BorderLayout.CENTER);
		new_job_panel.add(submitButton(), BorderLayout.SOUTH);
		add(new_job_panel);
		pack();
		setLocationRelativeTo(getRootPane());
		setVisible(true);
	}

	/**
	 * Returns a JPanel containing the submit and cancel buttons.
	 * 
	 * @return JPanel for buttons to display.
	 */
	private JPanel submitButton() {
		final JPanel submit_panel = new JPanel(new BorderLayout());
		final JButton submit_button = new JButton("Submit Job");
		submit_button.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent the_event) {
				createAndAddJob();
			}
		});
		final JButton cancel_button = new JButton("Cancel");
		cancel_button.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent the_event) {
				dispose();
			}
		});
		final JPanel align_panel = new JPanel(new FlowLayout());
		align_panel.add(cancel_button);
		align_panel.add(submit_button);
		submit_panel.add(align_panel, BorderLayout.EAST);
		return submit_panel;
	}

	/**
	 * Sets up the day field for the month passed. Changes the
	 * 
	 * @param the_date
	 *            The date to determine the number of days.
	 */
	private void setupDate(final GregorianCalendar the_date) {
		my_day.removeAllItems();
		for (int i = 1; i <= the_date
				.getActualMaximum(GregorianCalendar.DAY_OF_MONTH); i++) {
			my_day.insertItemAt(i, i - 1);
		}
	}

	/**
	 * Returns a GregorianCalendar for the selected items in the form.
	 * 
	 * @return GregorianCalendar a date selected from input.
	 */
	private GregorianCalendar getSelectedDate() {
		final int year = (Integer) my_year.getSelectedItem();
		final int month = my_month.getSelectedIndex();
		final int day = (Integer) my_day.getSelectedItem();
		int hour = (Integer) my_hour.getSelectedItem();
		final int ampm = my_ampm.getSelectedIndex();
		if (ampm == 0 && hour == 12) { // am
			hour = 0;
		} else if (ampm == 1 && hour != 12) { // pm
			hour += 12;
		}
		final int minute = (Integer) my_minute.getSelectedIndex();
		return new GregorianCalendar(year, month, day, hour, minute);
	}

	/**
	 * Returns a JPanel with the input components for creating a new job.
	 * 
	 * @return JPanel with the input.
	 */
	private JPanel entryPanel() {
		final JLabel park_name = new JLabel("Park Name:");
		park_name.setFont(GUIUtil.largerFont(park_name));
		my_park_list = new JComboBox();
		my_park_ids = new int[my_lm.getParksManaged().size()];
		int count = 0;
		for (Park p : my_lm.getParksManaged()) {
			my_park_list.insertItemAt(p.getName(), count);
			my_park_ids[count] = p.getID();
			count++;
		}
		my_park_list.setSelectedIndex(0);
		final JLabel desc = new JLabel("Description:");
		desc.setFont(GUIUtil.largerFont(desc));
		my_desc_field = new JTextField();
		final JLabel start_date = new JLabel("Start Date/Time:");
		start_date.setFont(GUIUtil.largerFont(start_date));
		final JLabel duration = new JLabel("Duration:");
		duration.setFont(GUIUtil.largerFont(duration));
		final JLabel vols_needed = new JLabel("Volunteers Needed:");
		vols_needed.setFont(GUIUtil.largerFont(vols_needed));

		final JPanel top_panel = new JPanel();
		top_panel.setLayout(new GridLayout(5, 1));
		top_panel.add(park_name);
		top_panel.add(my_park_list);
		top_panel.add(desc);
		top_panel.add(my_desc_field);
		top_panel.add(start_date);
		final JPanel mid_panel = startDatePanel();
		final JPanel bottom_panel = new JPanel();
		bottom_panel.setLayout(new GridLayout(4, 1));
		bottom_panel.add(duration);
		bottom_panel.add(durationPanel());
		bottom_panel.add(vols_needed);
		bottom_panel.add(volsNeededPanel());
		final JPanel entry_panel = new JPanel(new BorderLayout());
		entry_panel.add(top_panel, BorderLayout.NORTH);
		entry_panel.add(mid_panel, BorderLayout.CENTER);
		entry_panel.add(bottom_panel, BorderLayout.SOUTH);
		return entry_panel;
	}

	/**
	 * Returns a JPanel that is a subpanel containing the date components for
	 * the add job form.
	 * 
	 * @return JPanel subpanel of form.
	 */
	private JPanel startDatePanel() {
		// Year will never need to be more than year + 1;
		final JLabel year = new JLabel("Year");
		my_year = new JComboBox();
		final GregorianCalendar current = new GregorianCalendar();
		final int theyear = current.get(GregorianCalendar.YEAR);
		my_year.insertItemAt(theyear, 0);
		my_year.insertItemAt(theyear + 1, 1);
		my_year.setSelectedItem(theyear);
		my_month = new JComboBox();
		final JLabel month = new JLabel("Month");
		for (int i = 0; i < 12; i++) {
			my_month.insertItemAt(getMonth(i), i);
		}
		my_month.setSelectedIndex(current.get(GregorianCalendar.MONTH));
		my_day = new JComboBox();
		final JLabel day = new JLabel("Day");
		setupDate(current);
		// Day 1 is at index 0.
		my_day.setSelectedIndex(current.get(Calendar.DAY_OF_MONTH) - 1);
		ActionListener date_listener = new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent the_event) {
				setupDate(getSelectedDate());
				my_day.setSelectedIndex(0);
			}
		};
		my_year.addActionListener(date_listener);
		my_month.addActionListener(date_listener);

		my_hour = new JComboBox();
		final JLabel hour = new JLabel("Hour");
		for (int i = 0; i < 12; i++) {
			my_hour.insertItemAt(i + 1, i);
		}
		// Hour 1 is at index 0
		// Hour 12 is at index 11. GregorianCalendar treats hour 12 as hour 0,
		// so we must make a special check for this.
		int current_hour = current.get(Calendar.HOUR);
		if (current_hour != 0) {
			my_hour.setSelectedIndex(current.get(Calendar.HOUR) - 1);
		} else {
			my_hour.setSelectedIndex(11);
		}
		my_minute = new JComboBox();
		final JLabel minute = new JLabel("Minute");
		for (int i = 0; i < 60; i++) {
			my_minute.insertItemAt(String.format("%02d", i), i);
		}
		// Minute 0 is at index 0.
		my_minute.setSelectedIndex(current.get(Calendar.MINUTE));
		my_ampm = new JComboBox();
		final JLabel ampm = new JLabel("AM/PM");
		my_ampm.insertItemAt("AM", 0);
		my_ampm.insertItemAt("PM", 1);
		my_ampm.setSelectedIndex(current.get(Calendar.AM_PM));
		final JPanel start_date_panel = new JPanel(new GridLayout(4, 3));
		start_date_panel.add(month);
		start_date_panel.add(day);
		start_date_panel.add(year);
		start_date_panel.add(my_month);
		start_date_panel.add(my_day);
		start_date_panel.add(my_year);
		start_date_panel.add(hour);
		start_date_panel.add(minute);
		start_date_panel.add(ampm);
		start_date_panel.add(my_hour);
		start_date_panel.add(my_minute);
		start_date_panel.add(my_ampm);
		return start_date_panel;
	}

	/**
	 * Returns a JPanel for the sub-panel displaying the components for duration
	 * of the new job form.
	 * 
	 * @return JPanel to display duration sub panel.
	 */
	private JPanel durationPanel() {
		final JLabel days = new JLabel("Days");
		my_days = new JComboBox();
		for (int i = 0; i < 3; i++) {
			my_days.insertItemAt(i, i);
		}
		my_days.setSelectedIndex(0);
		my_hours = new JComboBox();
		final JLabel hours = new JLabel("Hours");
		for (int i = 0; i < 24; i++) {
			my_hours.insertItemAt(i, i);
		}
		my_hours.setSelectedIndex(0);
		my_minutes = new JComboBox();
		final JLabel minutes = new JLabel("Minutes");
		for (int i = 0; i < 60; i++) {
			my_minutes.insertItemAt(i, i);
		}
		my_minutes.setSelectedIndex(0);
		final JPanel duration_panel = new JPanel(new GridLayout(2, 3));
		duration_panel.add(days);
		duration_panel.add(hours);
		duration_panel.add(minutes);
		duration_panel.add(my_days);
		duration_panel.add(my_hours);
		duration_panel.add(my_minutes);
		return duration_panel;
	}

	/**
	 * Returns a JPanel with a sub-panel for the workload part of the new job
	 * form.
	 * 
	 * @return JPanel to display workload sub-panel.
	 */
	private JPanel volsNeededPanel() {
		final JLabel heavy = new JLabel("Heavy");
		my_heavy = new JTextField();

		final JLabel medium = new JLabel("Medium");
		my_medium = new JTextField();

		final JLabel light = new JLabel("Light");
		my_light = new JTextField();
		final JPanel vols_needed_panel = new JPanel(new GridLayout(2, 3));
		vols_needed_panel.add(heavy);
		vols_needed_panel.add(medium);
		vols_needed_panel.add(light);
		vols_needed_panel.add(my_heavy);
		vols_needed_panel.add(my_medium);
		vols_needed_panel.add(my_light);
		return vols_needed_panel;
	}

	/**
	 * Returns the String representation of the day of the month for the integer
	 * passed.
	 * 
	 * @param the_month
	 *            The number for of the month.
	 * @return String the month name.
	 */
	private String getMonth(final int the_month) {
		return new DateFormatSymbols().getMonths()[the_month];
	}

	/**
	 * Shows a dialog for when a job has been added successfully.
	 */
	private void jobAddSuccessful() {
		JOptionPane.showMessageDialog(this, "Your job has been added.",
				"Job Added", JOptionPane.INFORMATION_MESSAGE);
	}

	/**
	 * Helper method to add a job to the listmanager.
	 */
	private void createAndAddJob() {
		if (my_desc_field.getText().trim().length() == 0) {
			GUIUtil.errorMessage(this, "Please enter a description.");
		} else if (my_light.getText().trim().length() == 0) {
			GUIUtil.errorMessage(this,
					"Please enter the amount of light volunteers needed.");
		} else if (my_medium.getText().trim().length() == 0) {
			GUIUtil.errorMessage(this,
					"Please enter the amount of medium volunteers needed.");
		} else if (my_heavy.getText().trim().length() == 0) {
			GUIUtil.errorMessage(this,
					"Please enter the amount of heavy volunteers needed.");
		} else {
			final String name = my_desc_field.getText();
			final int id = my_park_ids[my_park_list.getSelectedIndex()];
			final GregorianCalendar start = getSelectedDate();
			final GregorianCalendar end = (GregorianCalendar) start.clone();
			end.add(GregorianCalendar.DATE, my_days.getSelectedIndex());
			end.add(GregorianCalendar.HOUR, my_hours.getSelectedIndex());
			end.add(GregorianCalendar.MINUTE, my_minutes.getSelectedIndex());
			try {
				final int light = Integer.parseInt(my_light.getText());
				final int med = Integer.parseInt(my_medium.getText());
				final int heavy = Integer.parseInt(my_heavy.getText());
				final Job j = new Job(name, id, start, end, light, med, heavy);
				try {
					my_lm.addJob(j);
					jobAddSuccessful();
					dispose();
					my_parent.jobAdded();
				} catch (final UPException upe) {
					GUIUtil.errorMessage(this, upe.getMessage());
				}
			} catch (final NumberFormatException nfe) {
				GUIUtil.errorMessage(this, "Number of volunteers incorrect "
						+ nfe.getMessage());
			}
		}
	}

}
